package com.nft.collection.service;

import java.io.IOException;
import java.security.MessageDigest;
import java.util.*;
import java.util.concurrent.TimeUnit;

import javax.validation.Valid;
import javax.validation.constraints.NotBlank;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.nft.collection.param.*;
import com.nft.collection.vo.*;
import com.nft.common.utils.IdUtils;
import com.nft.common.vo.Result;
import com.nft.dictconfig.domain.DictItem;
import com.nft.dictconfig.repo.DictItemRepo;
import org.apache.http.HttpResponse;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import com.nft.collection.domain.Collection;
import com.nft.collection.domain.IssuedCollectionActionLog;
import com.nft.collection.domain.MemberHoldCollection;
import com.nft.collection.domain.MemberResaleCollection;
import com.nft.collection.domain.MysteryBoxCommodity;
import com.nft.collection.domain.PayOrder;
import com.nft.collection.domain.PreSaleQualify;
import com.nft.collection.repo.CollectionRepo;
import com.nft.collection.repo.IssuedCollectionActionLogRepo;
import com.nft.collection.repo.MemberHoldCollectionRepo;
import com.nft.collection.repo.MemberResaleCollectionRepo;
import com.nft.collection.repo.PayOrderRepo;
import com.nft.collection.repo.PreSaleQualifyRepo;
import com.nft.common.exception.BizException;
import com.nft.common.utils.ThreadPoolUtils;
import com.nft.common.vo.PageResult;
import com.nft.constants.Constant;
import com.nft.log.domain.MemberBalanceChangeLog;
import com.nft.log.repo.MemberBalanceChangeLogRepo;
import com.nft.member.domain.Member;
import com.nft.member.repo.MemberRepo;
import com.nft.setting.domain.OperationSetting;
import com.nft.setting.repo.OperationSettingRepo;
import com.zengtengpeng.annotation.Lock;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.WeightRandom.WeightObj;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;

@Validated
@Service
public class TransactionService {

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private IssuedCollectionService issuedCollectionService;

    @Autowired
    private CollectionRepo collectionRepo;

    @Autowired
    private MemberHoldCollectionRepo memberHoldCollectionRepo;

    @Autowired
    private MemberRepo memberRepo;

    @Autowired
    private PayOrderRepo payOrderRepo;

    @Autowired
    private MemberBalanceChangeLogRepo memberBalanceChangeLogRepo;

    @Autowired
    private MemberResaleCollectionRepo memberResaleCollectionRepo;

    @Autowired
    private IssuedCollectionActionLogRepo issuedCollectionActionLogRepo;

    @Autowired
    private OperationSettingRepo operationSettingRepo;

    @Autowired
    private PreSaleQualifyRepo preSaleQualifyRepo;
    @Autowired
    private DictItemRepo dictItemRepo;
    @Value("${wuliu.appId}")
    private String wuLiuAppId;
    @Value("${wuliu.appSecret}")
    private String wuLiuAppSecret;

    @Transactional(readOnly = true)
    public MyPayOrderDetailVO findMyPayOrderDetail(@NotBlank String id) {
        PayOrder order = payOrderRepo.getOne(id);
        return MyPayOrderDetailVO.convertFor(order);
    }

    @Transactional(readOnly = true)
    public PageResult<PayOrderVO> findPayOrderByPage(@Valid PayOrderQueryCondParam param) {
        Page<PayOrder> result = payOrderRepo.findAll(param.buildSpecification1(),
                PageRequest.of(param.getPageNum() - 1, param.getPageSize(), Sort.by(Sort.Order.desc("createTime"))));
        PageResult<PayOrderVO> pageResult = new PageResult<>(PayOrderVO.convertFor(result.getContent()),
                param.getPageNum(), param.getPageSize(), result.getTotalElements());
        return pageResult;
    }

    @Transactional(readOnly = true)
    public PageResult<MyPayOrderVO> findMyPayOrderByPage(@Valid PayOrderQueryCondParam param) {
        Page<PayOrder> result = payOrderRepo.findAll(param.buildSpecification(),
                PageRequest.of(param.getPageNum() - 1, param.getPageSize(), Sort.by(Sort.Order.desc("createTime"))));
        PageResult<MyPayOrderVO> pageResult = new PageResult<>(MyPayOrderVO.convertFor(result.getContent()),
                param.getPageNum(), param.getPageSize(), result.getTotalElements());
        return pageResult;
    }

    @Transactional(readOnly = true)
    public PageResult<MyPayOrderVO> findMyPayOrderByDeliveryStatus(PayOrderQueryCondParam param) {
        Page<PayOrder> result = payOrderRepo.findAll(param.buildSpecification2(),
                PageRequest.of(param.getPageNum() - 1, param.getPageSize(), Sort.by(Sort.Order.desc("createTime"))));
        PageResult<MyPayOrderVO> pageResult = new PageResult<>(MyPayOrderVO.convertFor(result.getContent()),
                param.getPageNum(), param.getPageSize(), result.getTotalElements());
        return pageResult;
    }

    @Transactional
    public void payOrderTimeoutCancel() {
        Date now = new Date();
        List<PayOrder> payOrders = payOrderRepo.findByStateAndOrderDeadlineLessThan(Constant.支付订单状态_待付款, now);
        for (PayOrder payOrder : payOrders) {
            redissonClient.getTopic(Constant.支付订单超时取消).publish(payOrder.getId());
        }
    }

    @Transactional
    public void cancelPay(@Valid CancelPayParam param) {
        PayOrder payOrder = payOrderRepo.getOne(param.getOrderId());
        if (!payOrder.getMemberId().equals(param.getMemberId())) {
            throw new BizException("订单归属异常");
        }
        cancelPay(param.getOrderId());
    }

    @Transactional
    public void cancelPay(String orderId) {
        PayOrder payOrder = payOrderRepo.getOne(orderId);
        if (!Constant.支付订单状态_待付款.equals(payOrder.getState())) {
            throw new BizException("订单状态异常");
        }
        if (Constant.支付订单业务模式_平台自营.equals(payOrder.getBizMode())) {
            cancelPayWithLatestCollection(payOrder);
        } else if (Constant.支付订单业务类型_二级市场.equals(payOrder.getBizMode())) {
            cancelPayWithResaleCollection(payOrder);
        }

        ThreadPoolUtils.getRiskPool().schedule(() -> {
            redissonClient.getTopic(Constant.风控原因_下单未付款).publish(payOrder.getMemberId());
        }, 1, TimeUnit.SECONDS);
    }

    @Transactional
    public void payOrderCashback(String orderId) {
        PayOrder payOrder = payOrderRepo.getOne(orderId);
        if (Constant.支付订单业务模式_平台自营.equals(payOrder.getBizMode())) {
            CashbackWithLatestCollection(payOrder);
        } else if (Constant.支付订单业务类型_二级市场.equals(payOrder.getBizMode())) {
            CashbackWithLatestCollection(payOrder);
        }
    }

    public void cancelPayWithLatestCollection(PayOrder payOrder) {
        payOrder.cancelOrder();
        payOrderRepo.save(payOrder);
    }

    public void CashbackWithLatestCollection(PayOrder payOrder) {
        payOrder.CashbackOrder();
        payOrderRepo.save(payOrder);
    }
    public void cancelPayWithResaleCollection(PayOrder payOrder) {
        payOrder.cancelOrder();
        payOrderRepo.save(payOrder);

        MemberResaleCollection memberResaleCollection = memberResaleCollectionRepo.getOne(payOrder.getBizOrderNo());
        if (StrUtil.isNotBlank(memberResaleCollection.getLockPayMemberId())) {
            memberResaleCollection.setLockPayMemberId(null);
            memberResaleCollectionRepo.save(memberResaleCollection);
        }
    }

    @Transactional
    public void confirmPay(@Valid ConfirmPayParam param) {
        PayOrder payOrder = payOrderRepo.getOne(param.getOrderId());
        if (!Constant.支付订单状态_待付款.equals(payOrder.getState())) {
            throw new BizException("订单状态异常");
        }
        if (!payOrder.getMemberId().equals(param.getMemberId())) {
            throw new BizException("订单归属异常");
        }
        if (Constant.支付订单业务模式_平台自营.equals(payOrder.getBizMode())) {
            confirmPayWithLatestCollection(payOrder);
        } else if (Constant.支付订单业务类型_二级市场.equals(payOrder.getBizMode())) {
            confirmPayWithResaleCollection(payOrder);
        }
    }

    @Transactional
    public void marketConfirmPay(@Valid ConfirmPayParam param) {
        PayOrder payOrder = payOrderRepo.getOne(param.getOrderId());
        if (!Constant.支付订单状态_待付款.equals(payOrder.getState())) {
            throw new BizException("订单状态异常");
        }
        if (!payOrder.getMemberId().equals(param.getMemberId())) {
            throw new BizException("订单归属异常");
        }
        if (Constant.支付订单业务模式_平台自营.equals(payOrder.getBizMode())) {
            confirmPayWithMarketCollection(payOrder);
        } else if (Constant.支付订单业务类型_二级市场.equals(payOrder.getBizMode())) {
            confirmPayWithResaleCollection(payOrder);
        }
    }
    public void confirmPayWithResaleCollection(PayOrder payOrder) {
        Member buyer = payOrder.getMember();
        buyer.validBasicRisk();
        double balance = NumberUtil.round(buyer.getBalance() - payOrder.getAmount(), 2).doubleValue();
        if (balance < 0) {
            throw new BizException("余额不足");
        }

        MemberResaleCollection memberResaleCollection = memberResaleCollectionRepo.getOne(payOrder.getBizOrderNo());
        memberResaleCollection.sold();
        memberResaleCollectionRepo.save(memberResaleCollection);

        issuedCollectionService.resale(memberResaleCollection.getMemberHoldCollection(), buyer, payOrder);

        Member seller = memberResaleCollection.getMember();
        seller.setBalance(NumberUtil.round(seller.getBalance() + payOrder.getAmount(), 2).doubleValue());
        memberRepo.save(seller);

        Boolean boughtFlag = buyer.getBoughtFlag();
        if (!boughtFlag) {
            buyer.setBoughtFlag(true);
        }
        buyer.setBalance(balance);
        memberRepo.save(buyer);

        payOrder.paid();
        payOrderRepo.save(payOrder);

        memberBalanceChangeLogRepo.save(MemberBalanceChangeLog.buildWithSellCollection(seller, payOrder));
        memberBalanceChangeLogRepo.save(MemberBalanceChangeLog.buildWithBuyResaleCollection(buyer, payOrder));

        if (!boughtFlag) {
            ThreadPoolUtils.getRewardPool().schedule(() -> {
                redissonClient.getTopic(Constant.首单奖励).publish(buyer.getId());
            }, 1, TimeUnit.SECONDS);
        }
    }
    public void confirmPayWithMarketCollection(PayOrder payOrder) {
        Member member = payOrder.getMember();
        member.validBasicRisk();
        Collection collection = payOrder.getCollection();
        if (collection.getStock() <= 0) {
            throw new BizException("已售罄");
        }
        double balance = NumberUtil.round(member.getBalance() - collection.getPrice(), 2).doubleValue();
        if (balance < 0) {
            throw new BizException("余额不足");
        }

        PreSaleQualify preSaleQualify = null;

//            PreSaleQualify tmpPreSaleQualify = preSaleQualifyRepo
//                    .findTopByMemberIdAndCollectionIdAndStateOrderByPreMinuteDesc(member.getId(), collection.getId(),
//                            Constant.优先购资格状态_未使用);
//            if (tmpPreSaleQualify == null) {
//                throw new BizException("没有优先购的资格");
//            }
//            Date preMinuteAfterTime = DateUtil
//                    .offset(collection.getSaleTime(), DateField.MINUTE, -tmpPreSaleQualify.getPreMinute()).toJdkDate();
//            if (DateUtil.compare(new Date(), preMinuteAfterTime) < 0) {
//                throw new BizException(DateUtil.format(preMinuteAfterTime, "MM.dd HH:mm" + "之后才能抢购"));
//            }
//            preSaleQualify = tmpPreSaleQualify;


//        IssueResultVO firstIssueResultVO = issuedCollectionService.issue(collection, member.getId(),
//                Constant.藏品获取方式_购买);

        Boolean boughtFlag = member.getBoughtFlag();
        if (!boughtFlag) {
            member.setBoughtFlag(true);
        }
        member.setBalance(balance);
        memberRepo.save(member);

        payOrder.paid();
        payOrder.setCashbackTime(DateUtil.offset(new Date(), DateField.HOUR, collection.getCashbackArrivalTime()));
        payOrder.setCashbackAmount(collection.getCashbackAmount());
        payOrderRepo.save(payOrder);
        MemberHoldCollection memberHoldCollection = new MemberHoldCollection();
        memberHoldCollection.setId(IdUtils.getId());
        memberHoldCollection.setCollectionId(collection.getId());
        memberHoldCollection.setGainWay("1");
        memberHoldCollection.setHoldTime(new Date());
        memberHoldCollection.setMemberId(member.getId());
        memberHoldCollection.setPrice(collection.getPrice());
        memberHoldCollection.setState("1");
        memberHoldCollectionRepo.save(memberHoldCollection);

        //if (preSaleFlag) {
//            preSaleQualify.used(firstIssueResultVO.getIssuedCollectionId());
//            preSaleQualifyRepo.save(preSaleQualify);
       // }

        memberBalanceChangeLogRepo.save(MemberBalanceChangeLog.buildWithBuyLatestCollection(member, payOrder));

        if (!boughtFlag) {
            ThreadPoolUtils.getRewardPool().schedule(() -> {
                redissonClient.getTopic(Constant.首单奖励).publish(member.getId());
            }, 1, TimeUnit.SECONDS);
        }
    }
    public void confirmPayWithLatestCollection(PayOrder payOrder) {
        Member member = payOrder.getMember();
        member.validBasicRisk();
        Collection collection = payOrder.getCollection();
        if (collection.getStock() <= 0) {
            throw new BizException("已售罄");
        }
        double balance = NumberUtil.round(member.getBalance() - collection.getPrice(), 2).doubleValue();
        if (balance < 0) {
            throw new BizException("余额不足");
        }
        Boolean preSaleFlag = payOrder.getCreateTime().getTime() < collection.getSaleTime().getTime();
        PreSaleQualify preSaleQualify = null;
        if (preSaleFlag) {
            PreSaleQualify tmpPreSaleQualify = preSaleQualifyRepo
                    .findTopByMemberIdAndCollectionIdAndStateOrderByPreMinuteDesc(member.getId(), collection.getId(),
                            Constant.优先购资格状态_未使用);
            if (tmpPreSaleQualify == null) {
                throw new BizException("没有优先购的资格");
            }
            Date preMinuteAfterTime = DateUtil
                    .offset(collection.getSaleTime(), DateField.MINUTE, -tmpPreSaleQualify.getPreMinute()).toJdkDate();
            if (DateUtil.compare(new Date(), preMinuteAfterTime) < 0) {
                throw new BizException(DateUtil.format(preMinuteAfterTime, "MM.dd HH:mm" + "之后才能抢购"));
            }
            preSaleQualify = tmpPreSaleQualify;
        }

        IssueResultVO firstIssueResultVO = issuedCollectionService.issue(collection, member.getId(),
                Constant.藏品获取方式_购买);

        Boolean boughtFlag = member.getBoughtFlag();
        if (!boughtFlag) {
            member.setBoughtFlag(true);
        }
        member.setBalance(balance);
        memberRepo.save(member);

        payOrder.paid();
        payOrder.setCashbackTime(DateUtil.offset(new Date(), DateField.HOUR, collection.getCashbackArrivalTime()));
        payOrder.setCashbackAmount(collection.getCashbackAmount());
        payOrderRepo.save(payOrder);

        if (preSaleFlag) {
            preSaleQualify.used(firstIssueResultVO.getIssuedCollectionId());
            preSaleQualifyRepo.save(preSaleQualify);
        }

        memberBalanceChangeLogRepo.save(MemberBalanceChangeLog.buildWithBuyLatestCollection(member, payOrder));

        if (!boughtFlag) {
            ThreadPoolUtils.getRewardPool().schedule(() -> {
                redissonClient.getTopic(Constant.首单奖励).publish(member.getId());
            }, 1, TimeUnit.SECONDS);
        }
    }

    @Lock(keys = "'resaleCollectionCreateOrder' + #param.resaleCollectionId")
    @Transactional
    public String resaleCollectionCreateOrder(@Valid ResaleCollectionCreateOrderParam param) {
        MemberResaleCollection resaleCollection = memberResaleCollectionRepo.getOne(param.getResaleCollectionId());
        if (!Constant.转售的藏品状态_已发布.equals(resaleCollection.getState())) {
            throw new BizException("藏品状态异常");
        }
        if (StrUtil.isNotBlank(resaleCollection.getLockPayMemberId())
                && !resaleCollection.getLockPayMemberId().equals(param.getMemberId())) {
            throw new BizException("商品已被锁定");
        }
        PayOrder pendingOrder = payOrderRepo.findTopByMemberIdAndCollectionIdAndBizOrderNoAndState(param.getMemberId(),
                resaleCollection.getCollectionId(), resaleCollection.getId(), Constant.支付订单状态_待付款);
        if (pendingOrder != null) {
            return pendingOrder.getId();
        }
        Member buyer = memberRepo.getOne(param.getMemberId());
        buyer.validPlaceOrderRisk();
        if (buyer.getId().equals(resaleCollection.getMemberId())) {
            throw new BizException("不能购买自己的藏品");
        }

        if (StrUtil.isBlank(resaleCollection.getLockPayMemberId())) {
            resaleCollection.setLockPayMemberId(param.getMemberId());
            memberResaleCollectionRepo.save(resaleCollection);
        }

        Integer payOrderDeadline = operationSettingRepo.findTopByOrderByLatelyUpdateTime().getPayOrderDeadline();
        PayOrder payOrder = PayOrder.buildWithResaleCollection(resaleCollection, buyer, payOrderDeadline);
        payOrderRepo.save(payOrder);
        return payOrder.getId();
    }

    @Lock(keys = "'latestCollectionCreateOrder' + #param.memberId + #param.collectionId")
    @Transactional
    public String latestCollectionCreateOrder(@Valid LatestCollectionCreateOrderParam param) {
        OperationSetting operationSetting = operationSettingRepo.findTopByOrderByLatelyUpdateTime();
//		if (!operationSetting.getPrimaryMarketFun()) {
//			throw new BizException("未开放一级市场");
//		}
        PayOrder pendingOrder = payOrderRepo.findTopByMemberIdAndCollectionIdAndState(param.getMemberId(),
                param.getCollectionId(), Constant.支付订单状态_待付款);
        if (pendingOrder != null) {
            return pendingOrder.getId();
        }
        Member member = memberRepo.getOne(param.getMemberId());
        member.validPlaceOrderRisk();
        Collection collection = collectionRepo.getOne(param.getCollectionId());
        if (!collection.getExternalSaleFlag()) {
            throw new BizException("不对外发售");
        }
        Date now = new Date();
        if (now.getTime() - collection.getSaleTime().getTime() < 0) {
            if (collection.getPreSaleFlag()) {
                PreSaleQualify preSaleQualify = preSaleQualifyRepo
                        .findTopByMemberIdAndCollectionIdAndStateOrderByPreMinuteDesc(param.getMemberId(),
                                param.getCollectionId(), Constant.优先购资格状态_未使用);
                if (preSaleQualify == null) {
                    throw new BizException("没有优先购的资格");
                }
                Date preMinuteAfterTime = DateUtil
                        .offset(collection.getSaleTime(), DateField.MINUTE, -preSaleQualify.getPreMinute()).toJdkDate();
                if (DateUtil.compare(now, preMinuteAfterTime) < 0) {
                    throw new BizException(DateUtil.format(preMinuteAfterTime, "MM.dd HH:mm" + "之后才能抢购"));
                }
            } else {
                throw new BizException("未到发售时间");
            }
        }
        if (collection.getStock() <= 0) {
            throw new BizException("已售罄");
        }

        //Integer payOrderDeadline = operationSetting.getPayOrderDeadline();
        PayOrder payOrder = PayOrder.buildWithLatestCollection(collection, member, 15);
        payOrderRepo.save(payOrder);
        return payOrder.getId();
    }
    @Lock(keys = "'marketCollectionCreateOrder' + #param.memberId + #param.collectionId")
    @Transactional
    public String marketCollectionCreateOrder(@Valid LatestCollectionCreateOrderParam param) {
        OperationSetting operationSetting = operationSettingRepo.findTopByOrderByLatelyUpdateTime();
//		if (!operationSetting.getPrimaryMarketFun()) {
//			throw new BizException("未开放一级市场");
//		}
        PayOrder pendingOrder = payOrderRepo.findTopByMemberIdAndCollectionIdAndState(param.getMemberId(),
                param.getCollectionId(), Constant.支付订单状态_待付款);
        if (pendingOrder != null) {
            return pendingOrder.getId();
        }
        Member member = memberRepo.getOne(param.getMemberId());
        member.validPlaceOrderRisk();
        Collection collection = collectionRepo.getOne(param.getCollectionId());
        if (!collection.getExternalSaleFlag()) {
            throw new BizException("不对外发售");
        }
//        Date now = new Date();
//        if (now.getTime() - collection.getSaleTime().getTime() < 0) {
//            if (collection.getPreSaleFlag()) {
//                PreSaleQualify preSaleQualify = preSaleQualifyRepo
//                        .findTopByMemberIdAndCollectionIdAndStateOrderByPreMinuteDesc(param.getMemberId(),
//                                param.getCollectionId(), Constant.优先购资格状态_未使用);
//                if (preSaleQualify == null) {
//                    throw new BizException("没有优先购的资格");
//                }
//                Date preMinuteAfterTime = DateUtil
//                        .offset(collection.getSaleTime(), DateField.MINUTE, -preSaleQualify.getPreMinute()).toJdkDate();
//                if (DateUtil.compare(now, preMinuteAfterTime) < 0) {
//                    throw new BizException(DateUtil.format(preMinuteAfterTime, "MM.dd HH:mm" + "之后才能抢购"));
//                }
//            } else {
//                throw new BizException("未到发售时间");
//            }
//        }
        if (collection.getStock() <= 0) {
            throw new BizException("已售罄");
        }

        //Integer payOrderDeadline = operationSetting.getPayOrderDeadline();
        PayOrder payOrder = PayOrder.buildWithLatestCollection(collection, member, 15);
        payOrderRepo.save(payOrder);
        return payOrder.getId();
    }

    @Transactional
    public void cancelResale(@Valid CollectionCancelResaleParam param) {
        MemberResaleCollection resaleCollection = memberResaleCollectionRepo.getOne(param.getResaleCollectionId());
        if (!param.getMemberId().equals(resaleCollection.getMemberId())) {
            throw new BizException("无权操作该藏品");
        }
        cancelResaleInner(param.getResaleCollectionId());
    }

    @Transactional
    public void cancelResaleInner(@NotBlank String resaleCollectionId) {
        MemberResaleCollection resaleCollection = memberResaleCollectionRepo.getOne(resaleCollectionId);
        if (!Constant.转售的藏品状态_已发布.equals(resaleCollection.getState())) {
            throw new BizException("藏品归属异常");
        }
        if (StrUtil.isNotBlank(resaleCollection.getLockPayMemberId())) {
            throw new BizException("锁定支付中,不能取消");
        }

        resaleCollection.cancelResale();
        memberResaleCollectionRepo.save(resaleCollection);

        MemberHoldCollection memberHoldCollection = resaleCollection.getMemberHoldCollection();
        memberHoldCollection.setState(Constant.持有藏品状态_持有中);
        memberHoldCollectionRepo.save(memberHoldCollection);

        issuedCollectionActionLogRepo.save(IssuedCollectionActionLog.buildWithCancelResale(
                memberHoldCollection.getMemberId(), memberHoldCollection.getIssuedCollectionId()));
    }

    @Transactional
    public OpenMysteryBoxResultVO openMysteryBox(OpenMysteryBoxParam param) {
        MemberHoldCollection mysteryBox = memberHoldCollectionRepo.getOne(param.getHoldCollectionId());
        if (!param.getMemberId().equals(mysteryBox.getMemberId())) {
            throw new BizException("无权操作该商品");
        }
        if (!Constant.持有藏品状态_持有中.equals(mysteryBox.getState())) {
            throw new BizException("商品归属异常");
        }
        if (!Constant.商品类型_盲盒.equals(mysteryBox.getCollection().getCommodityType())) {
            throw new BizException("该商品不属于盲盒");
        }
        List<WeightObj<MysteryBoxCommodity>> weightCommoditys = new ArrayList<>();
        for (MysteryBoxCommodity mysteryBoxCommodity : mysteryBox.getCollection().getSubCommoditys()) {
            weightCommoditys.add(new WeightObj<>(mysteryBoxCommodity, mysteryBoxCommodity.getProbability()));
        }

        MysteryBoxCommodity randomCommodity = RandomUtil.weightRandom(weightCommoditys).next();
        Collection collection = randomCommodity.getCommodity();
        if (collection.getStock() <= 0) {
            throw new BizException("盲盒太火了，请稍后再打开");
        }

        issuedCollectionService.openMysteryBoxDestroy(mysteryBox);

        issuedCollectionService.issue(collection, param.getMemberId(), Constant.藏品获取方式_盲盒);
        return OpenMysteryBoxResultVO.build(collection.getName(), collection.getCover());
    }

    @Transactional
    public void collectionResale(@Valid CollectionResaleParam param) {
        OperationSetting operationSetting = operationSettingRepo.findTopByOrderByLatelyUpdateTime();
        if (!operationSetting.getConsignmentFun()) {
            throw new BizException("未开放寄售功能");
        }
        if (param.getResalePrice() < operationSetting.getConsignmentMinAmount()) {
            throw new BizException("价格不能少于" + operationSetting.getConsignmentMinAmount());
        }
        if (param.getResalePrice() > operationSetting.getConsignmentMaxAmount()) {
            throw new BizException("价格不能大于" + operationSetting.getConsignmentMaxAmount());
        }
        MemberHoldCollection memberHoldCollection = memberHoldCollectionRepo.getOne(param.getHoldCollectionId());
        if (!param.getMemberId().equals(memberHoldCollection.getMemberId())) {
            throw new BizException("无权操作该藏品");
        }
//        Date date = DateUtil.offset(memberHoldCollection.getHoldTime(), DateField.DAY_OF_YEAR,
//                operationSetting.getConsignmentLimitHoldDay()).toJdkDate();
//        if (date.getTime() > new Date().getTime()) {
//            throw new BizException("持有满" + operationSetting.getGiveLimitHoldDay() + "天才可以寄售");
//        }
        if (!Constant.持有藏品状态_持有中.equals(memberHoldCollection.getState())) {
            throw new BizException("藏品归属异常");
        }
        memberHoldCollection.setState(Constant.持有藏品状态_转售中);
        memberHoldCollectionRepo.save(memberHoldCollection);

        MemberResaleCollection resaleCollection = memberHoldCollection
                .buildResaleCollectionReocrd(param.getResalePrice());
        memberResaleCollectionRepo.save(resaleCollection);

        issuedCollectionActionLogRepo.save(IssuedCollectionActionLog.buildWithResale(resaleCollection.getResalePrice(),
                memberHoldCollection.getMemberId(), memberHoldCollection.getIssuedCollectionId()));
    }

    public void cashbackOrder() {
        Date now = new Date();
        List<PayOrder> payOrders = payOrderRepo.findByStateAndCashbackStatusAndCashbackTimeLessThan
                (Constant.支付订单状态_已付款, Constant.支付订单状态_未返现, now);
        for (PayOrder payOrder : payOrders) {
            redissonClient.getTopic(Constant.支付订单返现).publish(payOrder.getId());
        }
    }

    public LogisticsInfo submitShipping(SubmitShippingParam submitShippingParam) {
        PayOrder payOrderRepoOne = payOrderRepo.getOne(submitShippingParam.getOrderId());
        if(payOrderRepoOne ==null){
            throw  new BizException("订单不存在");
        }
        LogisticsCompanyParam logisticsCompany = submitShippingParam.getLogisticsCompany();
        LogisticsInfo logisticsInfo = getLogisticsInfo(logisticsCompany.getDictItemCode(), submitShippingParam.getExpressNumber());
        // 判断错误情况
            if (!logisticsInfo.isSuccess()) {
               throw  new BizException(logisticsInfo.getErrorMsg());
            } else {
                System.out.println("请求成功，物流信息：" + logisticsInfo);
                payOrderRepoOne.setExpressNumber(submitShippingParam.getExpressNumber());
                payOrderRepoOne.setDeliveryStatus(Constant.支付订单物流状态_已发货);
                payOrderRepoOne.setLogisticsCompany(submitShippingParam.getLogisticsCompany().getDictItemName());
                payOrderRepo.save(payOrderRepoOne);
                return logisticsInfo;
            }
}

    private LogisticsInfo getLogisticsInfo(String dictItemCode , String expressNumber) {
        //说明：请自行替换以下“xxx”的值
        String url = "http://express.xuanquetech.com/express/v2/queryExpressMap";//请求路径
//        String appId = "811bf25cb3fb4d81b5d6ea29c88a5017";//您的appid
//        String appSecret = "8da7ccdfc6284730a59aaf8b4c790ece";//您的appSecret
        //请求头
        Map<String, String> headers = new HashMap<>();
        headers.put("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
        //组装参数
        String requestData = "{\"cpCode\":\""+ dictItemCode+"\",\"mailNo\":\""+ expressNumber+"\"}";
        Map<String, String> params = new HashMap();
        params.put("appid", wuLiuAppId);
        params.put("sign", getSign(wuLiuAppSecret, requestData));//签名
        params.put("requestData", requestData);
        String resultData = httpPostWithForm(url, params, headers);// 发送post请求并接收返回结果
        System.out.println("--------->>>>"+resultData);
        // 解析结果
        LogisticsInfo logisticsInfo = null;
        try {
            ObjectMapper objectMapper = new ObjectMapper();
            logisticsInfo= objectMapper.readValue(resultData, LogisticsInfo.class);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return logisticsInfo;
    }


    public String findMyLogistics(String orderId) {
        Optional<PayOrder> byId = payOrderRepo.findById(orderId);
        PayOrder payOrder = byId.get();
        DictItem companyCode = dictItemRepo.findByDictTypeDictTypeCodeAndDictItemName("companyCode", payOrder.getLogisticsCompany());
        LogisticsInfo logisticsInfo = getLogisticsInfo(companyCode.getDictItemCode(), payOrder.getExpressNumber());
        return  logisticsInfo.getRouteMapUrl();
    }






    /***
     * 物流云服务
     */
    /**
     * 以form表单形式提交数据，发送post请求
     *
     * @param url
     * @param params
     * @param headers
     * @return
     */
    public static String httpPostWithForm(String url, Map<String, String> params, Map<String, String> headers) {
        // 用于接收返回的结果
        String resultData = "";
        try {
            HttpPost post = new HttpPost(url);
            //设置头部信息
            if (headers != null && !headers.isEmpty()) {
                for (Map.Entry<String, String> entry : headers.entrySet()) {
                    post.setHeader(entry.getKey(), entry.getValue());
                }
            }
            List<BasicNameValuePair> pairList = new ArrayList<>();
            for (String key : params.keySet()) {
                pairList.add(new BasicNameValuePair(key, params.get(key)));
            }
            UrlEncodedFormEntity uefe = new UrlEncodedFormEntity(pairList, "utf-8");
            post.setEntity(uefe);
            // 创建一个http客户端
            CloseableHttpClient httpClient = HttpClientBuilder.create().build();
            // 发送post请求
            HttpResponse response = httpClient.execute(post);
            resultData = EntityUtils.toString(response.getEntity(), "UTF-8");// 返回正常数据
        } catch (Exception e) {
            System.out.println("接口连接失败 e:" + e);
        }
        return resultData;
    }
    public static String getSign(String appSecret, String requestData) {
        String signValue = requestData + appSecret;//按顺序将参数拼接起来 如：requestData+appSecret
        System.out.println("原参数拼接:" + signValue);
        String md5SignValue = MD5Encode(signValue, "utf8");//形成MD5加密后的签名
        System.out.println("MD5加密:" + md5SignValue);
        return md5SignValue;
    }
    /**
     * MD5加密
     *
     * @param origin      字符
     * @param charsetname 编码
     * @return
     */
    public static String MD5Encode(String origin, String charsetname) {
        String resultString = null;
        try {
            resultString = new String(origin);
            MessageDigest md = MessageDigest.getInstance("MD5");
            if (null == charsetname || "".equals(charsetname)) {
                resultString = byteArrayToHexString(md.digest(resultString.getBytes()));
            } else {
                resultString = byteArrayToHexString(md.digest(resultString.getBytes(charsetname)));
            }
        } catch (Exception e) {
        }
        return resultString;
    }


    public static String byteArrayToHexString(byte b[]) {
        StringBuffer resultSb = new StringBuffer();
        for (int i = 0; i < b.length; i++) {
            resultSb.append(byteToHexString(b[i]));
        }
        return resultSb.toString();
    }
    private static final String hexDigIts[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"};
    public static String byteToHexString(byte b) {
        int n = b;
        if (n < 0) {
            n += 256;
        }
        int d1 = n / 16;
        int d2 = n % 16;
        return hexDigIts[d1] + hexDigIts[d2];
    }



}
